<?php
//рус
class search extends model_prototype_class
{

    private $_requestWords = array();
    
    public function IndexAllContent()
    {
        @set_time_limit(600);

        $this->ClearAllIndex();
        
        foreach ($this->_config->indexElements as $callBack)
        {    
            list($mod, $method) = explode('::', $callBack);
            if (!isset($this->_mods->$mod)) continue;
            if (!method_exists($this->_mods->$mod, $method)) continue;

            $data = $this->_mods->$mod->$method();
            if (!is_array($data) || !sizeof($data)) continue;
            
            while (list(, $record) = each($data))
            {
                $record['title'] = $this->StripHTML($record['title']);
				$record['body'] = $this->StripHTML($record['body']);
				
                $this->_libs->db->exec("insert into indexing_link(url, title, body)
									            values(
									            		  " . $this->_libs->db->quote($record['url']) . ",
											              " . $this->_libs->db->quote($record['title']) . ",
											              " .$this->_libs->db->quote($record['body']). "
										             )
							            "); 

				$id = $this->_libs->db->lastInsertID();
				
				$this->IndexRecord($id, $record['body'], 1);
				$this->IndexRecord($id, $record['title'], 50);
            }
        }
        
        $obj = SysLoader::GetModResponse();
        $obj->SetStatus(MR_STATUS_OK);
        $obj->SetMessage('Сайт проиндексирован');

        return $obj; 
    }
    
	private function IndexRecord($id, $text, $rang) 
	{        
        $wordsArr = $this->PrepareWords($text);        

		if (sizeof($wordsArr)) 
		{
			$wordsInDB = $this->_libs->db->query("select id, word from indexing_word where word in ('".implode("','",array_keys($wordsArr))."')")->fetchAll();
			
			$wordsIds = array();
			while (list(, $rec) = each($wordsInDB)) 
			{    
			    $wordsIds[$rec['word']] = $rec['id'];
			}
  
			while (list($word, $count) = each($wordsArr)) 
			{
				$wordRang = $rang*$count;
				
				if (!$wordId = $wordsIds[$word]) 
				{    
				    $this->_libs->db->exec("insert into indexing_word (word) values (" .$this->_libs->db->quote($word). ")");
				    $wordId = $this->_libs->db->lastInsertID();
				}

				if ($wordId) $this->_libs->db->exec("replace into indexing_index (link, word, times) values (" .$id. ", " .$wordId. ", " .$wordRang. ")");
			}
		}
	}    
    
	private function PrepareWords($text, $isAllForms = false)
	{ 
	    $text = $this->_libs->str->ToUpper(preg_replace('/[^\w\pL]/u', ' ', $text));      
	    $origWordsRate = array_count_values(preg_split('/[\s]+/u', $text, -1,PREG_SPLIT_NO_EMPTY));
	    
	    if (!$isAllForms) $words = $this->_libs->morphy->getBaseForm(array_keys($origWordsRate));        
        else $words = $this->_libs->morphy->getAllForms(array_keys($origWordsRate));  
	    
		$pWords = array();
        while (list($realWord, $baseForms) = each($words))
        {
            if (!is_array($baseForms)) 
            {
                if (!$baseForms) $baseForms = $realWord; 
                $baseForms = array($baseForms);                
            }

            foreach ($baseForms as $baseForm)                
            {
                if ($this->_libs->str->Len($baseForm) < 2) continue;
                if (!isset($pWords[$baseForm])) $pWords[$baseForm] = 0;
                $pWords[$baseForm] += $origWordsRate[$realWord];
            }         	    
        }		
		
        $missingWords = array_diff(array_keys($origWordsRate), array_keys($words)); 
        while (list(, $word) = each($missingWords))
        { 
            if ($this->_libs->str->Len($word) < 2) continue;
            $pWords[$word] = $origWordsRate[$word];  
        }
        
        return $pWords; 
	}
	
	private function StripHTML($html) 
	{
		$html = $this->_libs->str->StripTags($html);
		return $this->_libs->str->HTMLEntityDecode($html, true);
	}  

	private function ClearAllIndex()
	{
        $this->_libs->db->exec('TRUNCATE TABLE indexing_index');
        $this->_libs->db->exec('TRUNCATE TABLE indexing_link');	    
	}
    
	public function DoSearch($input)
	{
        $obj = SysLoader::GetModResponse();
        
        $str = $this->_libs->str->SubStr($input->str, 0, 60);
        
        $this->_requestWords = array_keys($this->PrepareWords($str, true));
        usort($this->_requestWords, array($this, 'SortWordsByLength'));

        $obj->total = 0;
        $obj->data = array();
        $obj->paginator = $this->_mods->Get('paginator'); 
        
        if (sizeof($this->_requestWords))
        {
            $sqlPreparedWords = array_map(array($this->_libs->db, 'quote'), $this->_requestWords);
            
			$obj->total = $this->_libs->db->query("select 
														count(distinct il.id)
													from 
														indexing_link il, 
														indexing_index ii, 
														indexing_word iw
													where 
														iw.word in (" .implode(',', $sqlPreparedWords). ") and 
														ii.word=iw.id and 
														il.id=ii.link")->fetchColumn();             
            
			$obj->paginator->Init($obj->total, $input->page, $input->onPage);

			$obj->data = $this->_libs->db->query("select 
														il.id,
														il.url,
														il.title,
														il.body, 
														count(distinct iw.id)*1000 + sum(ii.times) as rel
													from 
														indexing_link il, 
														indexing_index ii, 
														indexing_word iw
													where 
														iw.word in (" .implode(',', $sqlPreparedWords). ") and 
														ii.word=iw.id and 
														il.id=ii.link
													group by il.id 
													order by rel desc
													LIMIT " . $obj->paginator->GetSqlLimit())->fetchAll();        
        }
       
        $obj->SetStatus(MR_STATUS_OK);

        return $obj;
	}
	
	public function SortWordsByLength($x, $y)
	{
        $xLen = $this->_libs->str->Len($x);
        $yLen = $this->_libs->str->Len($y);	
        if ($xLen == $yLen) return 0;
        return ($xLen < $yLen) ? 1 : -1;            
	}
	
	public function HighLighter($txt) 
	{
	    if (!sizeof($this->_requestWords)) return htmlspecialchars($txt);

	    $pregWords = array_map('preg_quote', $this->_requestWords);

        if (!preg_match_all('#(?<=^|[^\w\pL])(?:.{0,60})(?:^|[^\w\pL])(?:' . implode('|', $pregWords) . ')(?:[^\w\pL]|$)(?:.{0,60})(?=[^\w\pL]|$)#isu', $txt, $matches, PREG_SET_ORDER)) 
        {            
            if (preg_match('/^.{0,100}[^\w\pL]/u', $txt, $match))
            {
                return htmlspecialchars($match[0]). '...';  
            }
            
            return htmlspecialchars($txt);
        }
            
        $txt = '...';
        $c = 0;
        foreach ($matches as $match)
        { 
            $txt .= preg_replace('#(?<=^|[^\w\pL])(' . implode('|', $pregWords) . ')(?=[^\w\pL]|$)#isu', '<b>$1</b>', htmlspecialchars($match[0])). '...';            
            if ($c++ > 0) return $txt;
        }     

        return $txt;
    }	
	
}